package yanivosher.aiproject;

import java.util.ArrayList;
import java.util.LinkedList;

public class GraphSearchState {

	Graph graph;
	int HeuristicCost = Integer.MAX_VALUE;
	int CostFromStart = Integer.MAX_VALUE;
	Step step;
	public Vertex vertex = null;
	public GraphSearchState previous = null;
	Agent agent;
	
	public GraphSearchState(GraphSearchState previous,Step step) {
		this.agent = previous.agent;
		this.graph = calcStep(previous.graph,step);
		this.previous = previous;
		this.step = step;
		this.vertex = graph.getVertexById(step.destination.getId());
		calculateHeuristicValue();
		this.CostFromStart = previous.CostFromStart + this.calcStepCost(graph, step);
	}
	
	public GraphSearchState(Vertex vertex,GraphSearchState previous,Graph graph, Agent agent) {
		this.vertex = vertex;
		this.previous = previous;
		this.graph = graph;
		this.agent = agent;
		calculateHeuristicValue();
		this.CostFromStart = 0;
	}
	
	public void calculateHeuristicValue() {
		int cost = 0;
		for (Vertex v : graph.getChemVertexes()) {
			LinkedList<Vertex> trip = DijkstraAlgorithm.getShortestPath(graph,v,graph.getVertexById(agent.destinationVertex.getId()));
			cost += graph.getPathCost(trip)*2;
		}
		this.HeuristicCost = cost;
		//System.out.println("state HeuristicCost = " + this.HeuristicCost);
	}
	
	public Graph calcStep(Graph graph,Step step)
	{
		Graph retGraph = graph.duplicateGraph();
		Vertex stepSrc = retGraph.getVertexById(step.current.getId());
		Vertex stepDest = retGraph.getVertexById(step.destination.getId());
		
		if (!step.getNoMove() ) {
			Edge e = retGraph.getEdgeBySourceDestination(stepSrc, stepDest);
			if(e == null)
			{
				Exception e1 = new Exception("Edge in Step cannot be null!!!");
				e1.printStackTrace();
			}
			if (e.getIsBlocked() && step.military && !step.chem) {
				retGraph.removeTerroristFromEdge(stepSrc,stepDest);
			}
			if (step.military) {
				stepSrc.setMilitary(stepSrc.getMilitary() - 1);
				stepDest.setMilitary(stepDest.getMilitary() + 1);
			}
			if (step.chem) {
				stepSrc.setChem(stepSrc.getChem() - 1);
				stepDest.setChem(stepDest.getChem() + 1);
			}
			//System.out.println("Moving from " + step.current.getId() + " to " + step.destination.getId());
		}
		if (step.destination.getId().equals(agent.destinationVertex.getId()) && stepDest.getChem()>0) {
			stepDest.setChem(0);
		}
		if (step.current.getId().equals(agent.destinationVertex.getId()) && stepSrc.getChem()>0) {
			stepDest.setChem(0);
		}
		return retGraph;
	}
	
	public int calcStepCost(Graph graph,Step step)
	{
		Vertex stepSrc = graph.getVertexById(step.current.getId());
		Vertex stepDest = graph.getVertexById(step.destination.getId());
		
		int cost = 0;
		if (!step.getNoMove() ) {
			Edge e = graph.getEdgeBySourceDestination(stepSrc, stepDest);
			if(e == null)
			{
				Exception e1 = new Exception("Edge in Step cannot be null!!!");
				e1.printStackTrace();
			}
			cost = e.getWeight();
			
			if (e.getIsBlocked() && step.chem && !step.military) {
				cost = Environment.getInstance().hellBreaksLooseCost;
			}
			if (step.military) {
				cost *= 2;
			}
			if (step.chem) {
				cost *= 2;
			}
			//System.out.println("Moving from " + step.current.getId() + " to " + step.destination.getId());
		}
		else
		{
			cost += Environment.getInstance().noOpCost;		
		}
		return cost;
	}

	public boolean isStateInGoal()
	{
		return graph.getChemVertexes().size() == 0;
	}

	public ArrayList<GraphSearchState> getChildStates() {
		ArrayList<GraphSearchState> retList = new ArrayList<GraphSearchState>();
		for (Edge edge : graph.getNeighborsEdges(vertex)) {
			retList.add(new GraphSearchState(this,new Step(edge.getDestination(),vertex,false,false)));
			if (vertex.getChem() > 0 && !edge.getIsBlocked()) {
				retList.add(new GraphSearchState(this,new Step(edge.getDestination(),vertex,true,false)));
			}
			if (vertex.getMilitary() > 0) {
				retList.add(new GraphSearchState(this,new Step(edge.getDestination(),vertex,false,true)));
			}
			if (vertex.getMilitary() > 0 && vertex.getChem() > 0) {
				retList.add(new GraphSearchState(this,new Step(edge.getDestination(),vertex,true,true)));
			}
		}
		return retList;
	}


	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		GraphSearchState other = (GraphSearchState) obj;
		if (graph == null) {
			if (other.graph != null)
				return false;
		} else if (!graph.equals(other.graph))
			return false;
		if (previous == null) {
			if (other.previous != null)
				return false;
		} else if (!previous.equals(other.previous))
			return false;
		if (step == null) {
			if (other.step != null)
				return false;
		} else if (!step.equals(other.step))
			return false;
		if (vertex == null) {
			if (other.vertex != null)
				return false;
		} else if (!vertex.equals(other.vertex))
			return false;
		return true;
	}
	
}
